package microcredit.model.bo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import microcredit.model.Member;
import microcredit.model.MemberGroup;
import microcredit.model.MemberToGroup;
import microcredit.model.ValidationException;
import microcredit.model.domain.Status;

public class BOMemberGroup extends BOBase {

	
	@SuppressWarnings("unchecked")
	public List<MemberGroup> readMemberGroups() {
		try {
			open();
			Query q = manager.createQuery("SELECT m FROM MemberGroup m");
			List<MemberGroup> member = (List<MemberGroup>)q.getResultList();
			commit();
			return member;
		} finally {
			close();
		}
	}
	
	public void unassignMemberToGroup(MemberToGroup group) {
		open();
		try  {
			BOMember boMember = new BOMember();
			boMember.connectSession(this);
			
			group.getMember().setGroup(null);
			boMember.saveMember(group.getMember());
			
			commit();
		} finally {
			close();
		}
		
	}
	
	public List<MemberToGroup> assignMembersToGroup(List<Member> members, MemberGroup group) {
		open();
		try  {
			BOMember boMember = new BOMember();
			boMember.connectSession(this);
			List<MemberToGroup> memberToGroups = new ArrayList<MemberToGroup>();
			for (Member member : members) {
				Member freshMember = boMember.getMember(member.getId());
				freshMember.setGroup(group);
				try {
					boMember.saveMember(freshMember);
				} catch (ValidationException e) {
					throw new ValidationException("Assigning group for "+freshMember.getFullName()+" failed: \n"+e.getMessage());
				}
			}
			commit();
			for (Member member : members) {
				if (member.getMemberToGroups().size() > 0) {
					memberToGroups.add(member.getMemberToGroups().get(member.getMemberToGroups().size()-1));
				}
			}
			return memberToGroups;
		} finally {
			close();
		}
	}
	
	public List<MemberToGroup> readMemberToGroups(Long groupID) {
		try {
			open();
			TypedQuery<MemberToGroup> q = manager.createQuery("SELECT m FROM MemberToGroup m WHERE m.status=:active AND m.memberGroupID=:groupID", MemberToGroup.class);
			q.setParameter("active", Status.A);
			q.setParameter("groupID", groupID);
			return q.getResultList();
		} finally {
			close();
		}
	}
	
	public MemberGroup saveMemberGroup(MemberGroup group) throws ValidationException {
		try {
			open();
			validateMemberGroup(group);
			
			group = manager.merge(group);
			
			commit();
		} finally {
			close();
		}
		return group;
	}
	
	
	private void validateMemberGroup(MemberGroup group) throws ValidationException {
		if (nullOrEmpty(group.getShortName())) {
			throw new ValidationException("Please enter a short name", MemberGroup.SHORT_NAME);
		}
		if (nullOrEmpty(group.getName())) {
			throw new ValidationException("Please enter a name", MemberGroup.NAME);
		} 
		
		TypedQuery<Long> query;
		if (group.getId() == null) {
			query = manager.createQuery("SELECT count(g) FROM MemberGroup g WHERE " +
					" g.shortName=:shortName", Long.class);			
		} else {
			query = manager.createQuery("SELECT count(g) FROM MemberGroup g WHERE " +
					" g.shortName=:shortName AND g.id <> :id ", Long.class);
			query.setParameter("id", group.getId());
		}
		query.setParameter("shortName", group.getShortName());
	
		long count = query.getSingleResult();
		if (count > 0) {
			throw new ValidationException("The short name '"+group.getShortName()+"' is already used by another group.");
		}
	}
	
	public void deleteMemberGroup(MemberGroup m) {
		try {
			open();
			m = manager.merge(m);
			manager.remove(m);
			commit();
		} catch (PersistenceException pE) {
			if (handleIntegrity(pE)) {
				throw new ValidationException("Could not delete. Members were or are already assigned. Please deactivate group instead.", pE);
			}
		 }finally {
			close();
		}
	}
	
	public static BOMemberGroup create() {
		return new BOMemberGroup();
	}
	
}
